﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Timers;

namespace BattleTetrixReloaded
{
    public class tet_game_loop
    {
        KeyboardState oldKeyboardState;        
        public bool isGameStarted = false;
        char nextShape;
        public Timer timer;
        public static int level = 1;
        List<Vector2> nextPiecePositions;        
        double elapsedFrames = 0;
        int[,] gameMatrix;
        char[] shapes = { 'i', 'j', 'l', 'o', 's', 'z', 't' };
        tet_constants game = new tet_constants();
        tet_shapes myShapes = new tet_shapes();
        public tet_score myScore = new tet_score();
        Random random;
        char currentShape;
        public int currentRotation, currentAnchorRow, currentAnchorColumn, shadowAnchorRow, shadowAnchorColumn, usedShapesNr = 0, clearedLines = 0;
        public char[] currentBlocks = new char[10000];
        int[,] shadow;
        public char[,] colorMatrix;
        public bool isGameOver;

        public tet_game_loop()
        {
            nextPiecePositions = new List<Vector2>();
            nextPiecePositions.Add(new Vector2(tet_main.boardPosition.X + 540, 40));
            nextPiecePositions.Add(new Vector2(tet_main.boardPosition.X + 540, 253));
            nextPiecePositions.Add(new Vector2(tet_main.boardPosition.X + 540, 465));
            nextPiecePositions.Add(new Vector2(tet_main.boardPosition.X + 540, 678));
            nextPiecePositions.Add(new Vector2(tet_main.boardPosition.X + 540, 890));

            gameMatrix = new int[20, 10];
            colorMatrix = new char[20, 10];

            for (int row = 0; row < 20; row++)
                for (int column = 0; column < 10; column++)
                {
                    colorMatrix[row, column] = 'w';                    
                    gameMatrix[row, column] = 0;
                }           

            usedShapesNr = 0;
            clearedLines = 0;
            myScore.resetScore();
            initializePieces();

            pushNewPiece();

            isGameStarted = true;

            timer = new Timer();
            timer.Elapsed += new ElapsedEventHandler(autodrop);
            timer.Interval = 1000;
            timer.Enabled = true;

            isGameOver = false;
            
        }

        private void autodrop(Object source, ElapsedEventArgs e)
        {
            if (clearedLines > level * 10)
            {
                timer.Interval = 1000 - level * 50;
                level++;
            }

            if (!moveCurrentShapeDown("STEP"))
            {
                timer.Enabled = false;
                tet_main.gameState = tet_constants.STATE_GAMEOVER;
            }
        }

        public void Update(GameTime gameTime)
        {
            elapsedFrames++;            

            KeyboardState newKeyboardState = Keyboard.GetState();


            if (oldKeyboardState.IsKeyUp(Keys.Escape) && newKeyboardState.IsKeyDown(Keys.Escape))
            {
                timer.Enabled = false;
                tet_main.gameState = tet_constants.STATE_PAUSED;
            }

            if (oldKeyboardState.IsKeyUp(Keys.Up) && newKeyboardState.IsKeyDown(Keys.Up))
            {
                rotateCurrentShape();
            }

            if (newKeyboardState.IsKeyDown(Keys.Right))
            {
                if (elapsedFrames % 5 == 0)
                {
                    moveCurrentShape(1);                    
                }
            }

            if (newKeyboardState.IsKeyDown(Keys.Left))
            {
                if (elapsedFrames % 5 == 0)
                {                    
                    moveCurrentShape(-1);
                }
            }

            if (newKeyboardState.IsKeyDown(Keys.Down))
            {
                if (elapsedFrames % 2 == 0)
                {
                    if (!moveCurrentShapeDown("STEP"))
                    {
                        if (tet_main.gameState == tet_constants.STATE_PLAYING_VS)
                        {
                            isGameOver = true;
                            timer.Enabled = false;
                            tet_main.gameState = tet_constants.STATE_VS_LOSE;
                        }
                        else
                        {
                            timer.Enabled = false;
                            tet_main.gameState = tet_constants.STATE_GAMEOVER;
                        }
                    }
                    myScore.addSoftDropBonus();
                }
            }            
            
            nextShape = currentBlocks[usedShapesNr + 1];

            for (int i = 0; i < tet_main.bonusQueue.Count; i++)
            {
                tet_main.bonusQueue[i].update();

                if (tet_main.bonusQueue[i].transparency < 0)
                {
                    tet_main.bonusQueue.RemoveAt(i);
                    i--;
                }
            }

            oldKeyboardState = newKeyboardState;           
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(tet_main.background, new Vector2(0, 0), Color.White);

            spriteBatch.DrawString(tet_main.testFont, elapsedFrames.ToString(), new Vector2(1800, 1000), Color.Black);

            spriteBatch.Draw(tet_main.boardBackground, new Vector2(tet_main.boardPosition.X - 20, tet_main.boardPosition.Y - 20), Color.White);

            //draw shadow
            if (shadow != null)
            {
                spriteBatch.Draw(tet_main.blockTexture,
                    new Vector2(tet_main.boardPosition.X + shadowAnchorColumn * 50, tet_main.boardPosition.Y + shadowAnchorRow * 50),
                    new Color(100, 100, 100, 255));
                spriteBatch.Draw(tet_main.blockTexture,
                    new Vector2(tet_main.boardPosition.X + (shadowAnchorColumn + shadow[0, 1]) * 50, tet_main.boardPosition.Y + (shadowAnchorRow + shadow[0, 0]) * 50),
                    new Color(100, 100, 100, 255));
                spriteBatch.Draw(tet_main.blockTexture,
                    new Vector2(tet_main.boardPosition.X + (shadowAnchorColumn + shadow[1, 1]) * 50, tet_main.boardPosition.Y + (shadowAnchorRow + shadow[1, 0]) * 50),
                    new Color(100, 100, 100, 255));
                spriteBatch.Draw(tet_main.blockTexture,
                    new Vector2(tet_main.boardPosition.X + (shadowAnchorColumn + shadow[2, 1]) * 50, tet_main.boardPosition.Y + (shadowAnchorRow + shadow[2, 0]) * 50),
                    new Color(100, 100, 100, 255));
            }

            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 20; j++)
                {
                    switch (colorMatrix[j, i])
                    {
                        case 'j':
                            spriteBatch.Draw(tet_main.blockTexture, new Rectangle((int)tet_main.boardPosition.X + i * 50, (int)tet_main.boardPosition.Y + j * 50, 50, 50), Color.Blue);
                            break;
                        case 'i':
                            spriteBatch.Draw(tet_main.blockTexture, new Rectangle((int)tet_main.boardPosition.X + i * 50, (int)tet_main.boardPosition.Y + j * 50, 50, 50), Color.Cyan);
                            break;
                        case 's':
                            spriteBatch.Draw(tet_main.blockTexture, new Rectangle((int)tet_main.boardPosition.X + i * 50, (int)tet_main.boardPosition.Y + j * 50, 50, 50), Color.Green);
                            break;
                        case 'l':
                            spriteBatch.Draw(tet_main.blockTexture, new Rectangle((int)tet_main.boardPosition.X + i * 50, (int)tet_main.boardPosition.Y + j * 50, 50, 50), Color.Orange);
                            break;
                        case 'z':
                            spriteBatch.Draw(tet_main.blockTexture, new Rectangle((int)tet_main.boardPosition.X + i * 50, (int)tet_main.boardPosition.Y + j * 50, 50, 50), Color.Purple);
                            break;
                        case 't':
                            spriteBatch.Draw(tet_main.blockTexture, new Rectangle((int)tet_main.boardPosition.X + i * 50, (int)tet_main.boardPosition.Y + j * 50, 50, 50), Color.Red);
                            break;
                        case 'o':
                            spriteBatch.Draw(tet_main.blockTexture, new Rectangle((int)tet_main.boardPosition.X + i * 50, (int)tet_main.boardPosition.Y + j * 50, 50, 50), Color.Yellow);
                            break;
                    }
                }
            }

            

            drawNextPieces(spriteBatch, usedShapesNr);

            spriteBatch.DrawString(tet_main.testFont, "SCORE : " + myScore.getScore().ToString(), new Vector2(50, 110), Color.Black);
            spriteBatch.DrawString(tet_main.testFont, "LINES : " + clearedLines.ToString(), new Vector2(50, 140), Color.Black);
            spriteBatch.DrawString(tet_main.testFont, "LEVEL : " + level.ToString(), new Vector2(50, 170), Color.Black);
            spriteBatch.DrawString(tet_main.testFont, "MULTIPLIER : " + myScore.getScoreMultiplier().ToString(), new Vector2(50, 200), Color.Black);

            for (int i = 0; i < tet_main.bonusQueue.Count; i++)
            {
                tet_main.bonusQueue[i].draw(spriteBatch);
            }
        }

        private void drawNextPieces(SpriteBatch spriteBatch, int p)
        {
            drawPiece(spriteBatch, p + 1, nextPiecePositions[0]);
            drawPiece(spriteBatch, p + 2, nextPiecePositions[1]);
            drawPiece(spriteBatch, p + 3, nextPiecePositions[2]);
            drawPiece(spriteBatch, p + 4, nextPiecePositions[3]);
            drawPiece(spriteBatch, p + 5, nextPiecePositions[4]);
        }

        private void drawPiece(SpriteBatch spriteBatch, int p, Vector2 nextPiece1)
        {
            spriteBatch.Draw(tet_main.nextPieceBackground, new Vector2(nextPiece1.X - 20, nextPiece1.Y - 20), Color.White);

            switch (currentBlocks[p])
            {
                case 'i' :
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X, nextPiece1.Y + 50), Color.Cyan);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 50, nextPiece1.Y + 50), Color.Cyan);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 100, nextPiece1.Y + 50), Color.Cyan);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 150, nextPiece1.Y + 50), Color.Cyan);
                    break;
                case 'l':
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 25, nextPiece1.Y + 75), Color.Orange);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 25, nextPiece1.Y + 25), Color.Orange);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 75, nextPiece1.Y + 25), Color.Orange);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 125, nextPiece1.Y + 25), Color.Orange);
                    break;
                case 'j':
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 125, nextPiece1.Y + 75), Color.Blue);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 25, nextPiece1.Y + 25), Color.Blue);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 75, nextPiece1.Y + 25), Color.Blue);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 125, nextPiece1.Y + 25), Color.Blue);
                    break;
                case 's':
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 75, nextPiece1.Y + 25), Color.Green);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 125, nextPiece1.Y + 25), Color.Green);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 25, nextPiece1.Y + 75), Color.Green);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 75, nextPiece1.Y + 75), Color.Green);
                    break;
                case 'z':
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 25, nextPiece1.Y + 25), Color.Purple);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 75, nextPiece1.Y + 25), Color.Purple);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 75, nextPiece1.Y + 75), Color.Purple);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 125, nextPiece1.Y + 75), Color.Purple);
                    break;
                case 't':
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 75, nextPiece1.Y + 75), Color.Red);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 25, nextPiece1.Y + 25), Color.Red);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 75, nextPiece1.Y + 25), Color.Red);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 125, nextPiece1.Y + 25), Color.Red);
                    break;
                case 'o':
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 50, nextPiece1.Y + 25), Color.Yellow);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 100, nextPiece1.Y + 25), Color.Yellow);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 50, nextPiece1.Y + 75), Color.Yellow);
                    spriteBatch.Draw(tet_main.blockTexture, new Vector2(nextPiece1.X + 100, nextPiece1.Y + 75), Color.Yellow);
                    break;
            }
        }        

        public void calculateShadow()
        {
            shadow = getShape(currentShape, currentRotation);

            shadowAnchorRow = currentAnchorRow;
            shadowAnchorColumn = currentAnchorColumn;


            while (shadowAnchorRow < 19 && shadowAnchorRow + shadow[0, 0] < 19 && shadowAnchorRow + shadow[1, 0] < 19 && shadowAnchorRow + shadow[2, 0] < 19 && (
                gameMatrix[shadowAnchorRow + 1, shadowAnchorColumn] == 1 ||
                gameMatrix[shadowAnchorRow + 1 + shadow[0, 0], shadowAnchorColumn + shadow[0, 1]] == 1 ||
                gameMatrix[shadowAnchorRow + 1 + shadow[1, 0], shadowAnchorColumn + shadow[1, 1]] == 1 ||
                gameMatrix[shadowAnchorRow + 1 + shadow[2, 0], shadowAnchorColumn + shadow[2, 1]] == 1))
            {
                shadowAnchorRow++;
            }

            while (shadowAnchorRow < 19 && shadowAnchorRow + shadow[0, 0] < 19 && shadowAnchorRow + shadow[1, 0] < 19 && shadowAnchorRow + shadow[2, 0] < 19 &&
                gameMatrix[shadowAnchorRow + 1, shadowAnchorColumn] != 1 &&
                gameMatrix[shadowAnchorRow + 1 + shadow[0, 0], shadowAnchorColumn + shadow[0, 1]] != 1 &&
                gameMatrix[shadowAnchorRow + 1 + shadow[1, 0], shadowAnchorColumn + shadow[1, 1]] != 1 &&
                gameMatrix[shadowAnchorRow + 1 + shadow[2, 0], shadowAnchorColumn + shadow[2, 1]] != 1)
            {
                shadowAnchorRow++;
            }


        }

        public int[,] getShape(char shape, int rotation)
        {
            int[,] toModify = new int[3, 4];

            if (shape == 'i') toModify = myShapes.shapeI[rotation - 1];
            else if (shape == 'j') toModify = myShapes.shapeJ[rotation - 1];
            else if (shape == 'l') toModify = myShapes.shapeL[rotation - 1];
            else if (shape == 'o') toModify = myShapes.shapeO[rotation - 1];
            else if (shape == 's') toModify = myShapes.shapeS[rotation - 1];
            else if (shape == 'z') toModify = myShapes.shapeZ[rotation - 1];
            else if (shape == 't') toModify = myShapes.shapeT[rotation - 1];

            return toModify;
        }

        private void setShapeInColorMatrix(int[,] shape, char value)
        {
            colorMatrix[currentAnchorRow, currentAnchorColumn] = value;
            colorMatrix[currentAnchorRow + shape[0, 0], currentAnchorColumn + shape[0, 1]] = value;
            colorMatrix[currentAnchorRow + shape[1, 0], currentAnchorColumn + shape[1, 1]] = value;
            colorMatrix[currentAnchorRow + shape[2, 0], currentAnchorColumn + shape[2, 1]] = value;
        }

        private void setShapeInGameMatrix(int[,] shape, int value)
        {
            gameMatrix[currentAnchorRow, currentAnchorColumn] = value;
            gameMatrix[currentAnchorRow + shape[0, 0], currentAnchorColumn + shape[0, 1]] = value;
            gameMatrix[currentAnchorRow + shape[1, 0], currentAnchorColumn + shape[1, 1]] = value;
            gameMatrix[currentAnchorRow + shape[2, 0], currentAnchorColumn + shape[2, 1]] = value;
        }

        public void initializePieces()
        {
            generateBlocks();
        }       

        public void generateBlocks()
        {
            //TGM 2

            random = new Random();
            currentBlocks = new char[10000];
            char[] history = { 'z', 's', 'z', 's' };
            char rand;
            bool found;

            for (int i = 0; i < 10000; i++)
            {
                found = false;

                for (int j = 0; j < 6; j++)
                {
                    rand = shapes[random.Next(7)];
                    if (rand != history[0] && rand != history[1] && rand != history[2] && rand != history[3])
                    {
                        currentBlocks[i] = rand;
                        history[0] = history[1];
                        history[1] = history[2];
                        history[2] = history[3];
                        history[3] = rand;
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    rand = shapes[random.Next(7)];
                    currentBlocks[i] = rand;
                    history[0] = history[1];
                    history[1] = history[2];
                    history[2] = history[3];
                    history[3] = rand;
                }
            }
        }

        //private void decideIfStar()
        //{
        //    tet_random random = new tet_random();
        //    int highestBOnus = highestRowWithPieces(tet_constants.gameMatrix);
        //    if (highestBOnus != -1)//being and empty row
        //    {
        //        if (random.getRandomInt(tet_constants.CHANCE_POWERUP_STAR) == tet_constants.POWER_UP_OCCURED)
        //        {
        //            //this piece's powerup;
        //            int whatColumn = random.getRandomInt(10);
        //            int whatRow = random.getRandomInt(20 - highestBOnus);
        //            //try
        //            //{
        //            tet_constants.gameMatrix[19 - whatRow, whatColumn] = 1;
        //            tet_constants.colorMatrix[19 - whatRow, whatColumn] = 'p';

        //            Image image = Image.FromFile(tet_graphics.STAR);
        //            mainWindow.myGraphics.DrawImage(image, new Rectangle(260 + whatColumn * 30, 100 + (19 - whatRow) * 30, 30, 30));
        //            //}
        //            //catch
        //            //{
        //            //    //quick, dirty, slutty, filthy, disease ridden fix.
        //            //}
        //        }
        //    }
        //}

        public bool pushNewPiece()
        {
            currentShape = currentBlocks[usedShapesNr];
            currentRotation = 1;
            currentAnchorRow = 0;
            currentAnchorColumn = 5;

            int[,] shape = new int[3, 4];
            shape = getShape(currentShape, currentRotation);

            bool gameOver = isItPossible(shape);

            gameMatrix[currentAnchorRow, currentAnchorColumn] = 1;
            gameMatrix[currentAnchorRow + shape[0, 0], currentAnchorColumn + shape[0, 1]] = 1;
            gameMatrix[currentAnchorRow + shape[1, 0], currentAnchorColumn + shape[1, 1]] = 1;
            gameMatrix[currentAnchorRow + shape[2, 0], currentAnchorColumn + shape[2, 1]] = 1;

            colorMatrix[currentAnchorRow, currentAnchorColumn] = currentShape;
            colorMatrix[currentAnchorRow + shape[0, 0], currentAnchorColumn + shape[0, 1]] = currentShape;
            colorMatrix[currentAnchorRow + shape[1, 0], currentAnchorColumn + shape[1, 1]] = currentShape;
            colorMatrix[currentAnchorRow + shape[2, 0], currentAnchorColumn + shape[2, 1]] = currentShape;

            if (gameOver) return false;

            calculateShadow();

            return true;
        }

        public bool rotateCurrentShape()
        {
            while (currentAnchorRow == 0) moveCurrentShapeDown("STEP");

            bool wasSuccesfull = rotateFromX(currentRotation);

            calculateShadow();

            return wasSuccesfull;
        }

        public bool moveCurrentShape(int where)
        {
            int[,] shape = new int[3, 4];
            shape = getShape(currentShape, currentRotation);

            if (!isInBounds(where, shape)) return false;
            if (!icanMoveThere(gameMatrix, shape, where)) return false;

            if (where == 1) applyMoveToRight(shape);
            else applyMoveToLeft(shape);

            calculateShadow();

            return true;
        }

        internal bool moveCurrentShapeDown(string type)
        {
            int[,] shape = new int[3, 4];
            int[] removedPs = new int[10];
            bool isFinalMove = false;
            shape = getShape(currentShape, currentRotation);

            if (type == "SNAP")
            {
                myScore.addInstaDropBonus(20 - currentAnchorRow);
                while (!isFinalMove) isFinalMove = applyMoveDown(shape);
            }
            else isFinalMove = applyMoveDown(shape);

            if (isFinalMove)
            {
                int clearedLinesThisDrop = 0;
                int iCanStillRemove = removeOrNotAndWhat(gameMatrix);
                while (iCanStillRemove != -1)
                {
                    removedPs = doTheRemove(gameMatrix, iCanStillRemove);
                    for (int i = 0; i < 10; i++)
                    {
                        if (removedPs[i] == 'p')
                            myScore.addStarBonus();
                    }
                    clearedLinesThisDrop++;
                    iCanStillRemove = removeOrNotAndWhat(gameMatrix);

                }

                if (clearedLinesThisDrop != 0)
                {
                    myScore.addScoringMove(clearedLinesThisDrop);
                    clearedLines += clearedLinesThisDrop;

                    tet_main.bonusQueue.Add(new tet_bonus(tet_main.bonuses[clearedLinesThisDrop - 1]));
                }
                else myScore.addNonScoringMove();

                usedShapesNr++;

                if (!pushNewPiece()) return false;
            }

            return true;
        }

        private bool isItPossible(int[,] shape)
        {
            if (gameMatrix[currentAnchorRow, currentAnchorColumn] == 1) return true;
            if (gameMatrix[currentAnchorRow + shape[0, 0], currentAnchorColumn + shape[0, 1]] == 1) return true;
            if (gameMatrix[currentAnchorRow + shape[1, 0], currentAnchorColumn + shape[1, 1]] == 1) return true;
            if (gameMatrix[currentAnchorRow + shape[2, 0], currentAnchorColumn + shape[2, 1]] == 1) return true;

            return false;
        }

        private bool rotateFromX(int x)
        {
            int previousRotation = currentRotation;
            if (x != 4)
                currentRotation = x + 1;
            else
                currentRotation = 1;

            bool wasRotated = applyRotation(currentShape, currentRotation);

            if (!wasRotated) currentRotation = previousRotation;

            return wasRotated;

        }

        private bool applyRotation(char shape, int rotation)
        {
            if (currentAnchorRow == 0) return false;
            int[,] newPosition = new int[3, 4];
            newPosition = getShape(shape, rotation);

            int[,] oldPosition = new int[3, 4];
            if (rotation != 1) oldPosition = getShape(shape, rotation - 1);
            else oldPosition = getShape(shape, 4);

            int bounce = requiredBounce(newPosition, rotation);

            if (!iCanRotate(gameMatrix, oldPosition, newPosition, bounce)) return false;

            setShapeInGameMatrix(oldPosition, 0);
            setShapeInColorMatrix(oldPosition, 'w');

            currentAnchorColumn += bounce;

            setShapeInGameMatrix(newPosition, 1);
            setShapeInColorMatrix(newPosition, currentShape);

            return true;
        }

        private bool iCanRotate(int[,] gameMatrixReference, int[,] oldPosition, int[,] newPosition, int bounce)
        {
            int[,] gameMatrix = gameMatrixReference;

            int currentAnchorColumnReference = currentAnchorColumn + bounce;

            gameMatrix[currentAnchorRow, currentAnchorColumn] = 0;
            gameMatrix[currentAnchorRow + oldPosition[0, 0], currentAnchorColumn + oldPosition[0, 1]] = 0;
            gameMatrix[currentAnchorRow + oldPosition[1, 0], currentAnchorColumn + oldPosition[1, 1]] = 0;
            gameMatrix[currentAnchorRow + oldPosition[2, 0], currentAnchorColumn + oldPosition[2, 1]] = 0;

            if (gameMatrix[currentAnchorRow, currentAnchorColumn] == 1) return false;
            if (gameMatrix[currentAnchorRow + newPosition[0, 0], currentAnchorColumnReference + newPosition[0, 1]] == 1) return false;
            if (gameMatrix[currentAnchorRow + newPosition[1, 0], currentAnchorColumnReference + newPosition[1, 1]] == 1) return false;
            if (gameMatrix[currentAnchorRow + newPosition[2, 0], currentAnchorColumnReference + newPosition[2, 1]] == 1) return false;

            return true;
        }

        private int requiredBounce(int[,] newPosition, int rotation)
        {
            int bounce = 0;
            bool positive = true;

            if (currentAnchorColumn + newPosition[0, 1] > 9)
                if (currentAnchorColumn + newPosition[0, 1] - 9 > bounce)
                {
                    bounce = currentAnchorColumn + newPosition[0, 1] - 9;
                    positive = false;
                }
            if (currentAnchorColumn + newPosition[1, 1] > 9)
                if (currentAnchorColumn + newPosition[1, 1] - 9 > bounce)
                {
                    bounce = currentAnchorColumn + newPosition[1, 1] - 9;
                    positive = false;
                }
            if (currentAnchorColumn + newPosition[2, 1] > 9)
                if (currentAnchorColumn + newPosition[2, 1] - 9 > bounce)
                {
                    bounce = currentAnchorColumn + newPosition[2, 1] - 9;
                    positive = false;
                }

            if (positive)
            {
                if (currentAnchorColumn + newPosition[0, 1] < 0)
                    if (currentAnchorColumn + newPosition[0, 1] < bounce)
                    {
                        bounce = currentAnchorColumn + newPosition[0, 1];
                        //positive = true;
                    }
                if (currentAnchorColumn + newPosition[1, 1] < 0)
                    if (currentAnchorColumn + newPosition[1, 1] < bounce)
                    {
                        bounce = currentAnchorColumn + newPosition[1, 1];
                        //positive = false;
                    }
                if (currentAnchorColumn + newPosition[2, 1] < 0)
                    if (currentAnchorColumn + newPosition[2, 1] < bounce)
                    {
                        bounce = currentAnchorColumn + newPosition[2, 1];
                        //positive = false;
                    }
            }

            return -bounce;
        }

        private bool icanMoveThere(int[,] gameMatrix, int[,] shape, int where)
        {
            int[,] gameMatrixReference = gameMatrix;
            int anchorColumnReference = currentAnchorColumn;

            gameMatrixReference[currentAnchorRow, anchorColumnReference] = 0;
            gameMatrixReference[currentAnchorRow + shape[0, 0], anchorColumnReference + shape[0, 1]] = 0;
            gameMatrixReference[currentAnchorRow + shape[1, 0], anchorColumnReference + shape[1, 1]] = 0;
            gameMatrixReference[currentAnchorRow + shape[2, 0], anchorColumnReference + shape[2, 1]] = 0;

            anchorColumnReference += where;

            if (gameMatrixReference[currentAnchorRow, anchorColumnReference] == 1) return false;
            if (gameMatrixReference[currentAnchorRow + shape[0, 0], anchorColumnReference + shape[0, 1]] == 1) return false;
            if (gameMatrixReference[currentAnchorRow + shape[1, 0], anchorColumnReference + shape[1, 1]] == 1) return false;
            if (gameMatrixReference[currentAnchorRow + shape[2, 0], anchorColumnReference + shape[2, 1]] == 1) return false;

            return true;
        }

        private bool isInBounds(int anchorShift, int[,] shape)
        {
            if ((currentAnchorColumn + anchorShift > 9) || (currentAnchorColumn + anchorShift < 0)) return false;
            if ((currentAnchorColumn + anchorShift + shape[0, 1] > 9) || (currentAnchorColumn + anchorShift + shape[0, 1] < 0)) return false;
            if ((currentAnchorColumn + anchorShift + shape[1, 1] > 9) || (currentAnchorColumn + anchorShift + shape[1, 1] < 0)) return false;
            if ((currentAnchorColumn + anchorShift + shape[2, 1] > 9) || (currentAnchorColumn + anchorShift + shape[2, 1] < 0)) return false;

            return true;
        }

        private void applyMoveToRight(int[,] shape)
        {
            setShapeInGameMatrix(shape, 0);
            setShapeInColorMatrix(shape, 'w');

            currentAnchorColumn += 1;

            setShapeInGameMatrix(shape, 1);
            setShapeInColorMatrix(shape, currentShape);

        }

        private void applyMoveToLeft(int[,] shape)
        {
            setShapeInGameMatrix(shape, 0);
            setShapeInColorMatrix(shape, 'w');

            currentAnchorColumn -= 1;

            setShapeInGameMatrix(shape, 1);
            setShapeInColorMatrix(shape, currentShape);

        }

        private bool applyMoveDown(int[,] shape)
        {
            if (touchingLowerBound(shape))
            {
                setShapeInGameMatrix(shape, 1);
                setShapeInColorMatrix(shape, currentShape);
                return true;
            }

            setShapeInGameMatrix(shape, 0);
            setShapeInColorMatrix(shape, 'w');

            if ((gameMatrix[currentAnchorRow + 1, currentAnchorColumn] == 1) ||
                (gameMatrix[currentAnchorRow + 1 + shape[0, 0], currentAnchorColumn + shape[0, 1]] == 1) ||
                (gameMatrix[currentAnchorRow + 1 + shape[1, 0], currentAnchorColumn + shape[1, 1]] == 1) ||
                (gameMatrix[currentAnchorRow + 1 + shape[2, 0], currentAnchorColumn + shape[2, 1]] == 1))
            {
                setShapeInGameMatrix(shape, 1);
                setShapeInColorMatrix(shape, currentShape);
                return true;
            }

            currentAnchorRow += 1;

            setShapeInGameMatrix(shape, 1);
            setShapeInColorMatrix(shape, currentShape);

            return false;
        }

        private bool touchingLowerBound(int[,] shape)
        {
            if (currentAnchorRow + 1 > 19) return true;
            if (currentAnchorRow + shape[0, 0] + 1 > 19) return true;
            if (currentAnchorRow + shape[1, 0] + 1 > 19) return true;
            if (currentAnchorRow + shape[2, 0] + 1 > 19) return true;

            return false;
        }

        private int removeOrNotAndWhat(int[,] Matrix)
        {
            int lineToRemove = -1;
            int lineCandidate = -1;

            bool amIaFullLine = true;

            for (int i = 0; i < 20; i++)
            {
                lineCandidate = i;
                amIaFullLine = true;
                for (int j = 0; j < 10; j++)
                {
                    if (Matrix[i, j] == 0)
                        amIaFullLine = false;
                }

                if (amIaFullLine == true)
                    return lineCandidate;
            }

            return lineToRemove;
        }

        private int[] doTheRemove(int[,] Matrix, int lineToRemove)
        {
            int[] returnVec = new int[10];
            for (int i = 0; i < 10; i++)
            {
                returnVec[i] = Matrix[lineToRemove, i];
            }

            for (int i = lineToRemove; i > 0; i--)
                for (int j = 0; j < 10; j++)
                {
                    //if (tet_constants.colorMatrix[i, j] == 'p')
                    //{
                    //    myScore.addStarBonus();
                    //}
                    colorMatrix[i, j] = colorMatrix[i - 1, j];
                    Matrix[i, j] = Matrix[i - 1, j];
                }
            return returnVec;
        }

        private int highestRowWithPieces(int[,] Matrix)
        {
            int returnRow = -1;
            for (int i = 4; i < 20; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    if (Matrix[i, j] == 1)
                    {
                        return i;
                    }
                }
            }

            return returnRow;
        }
    }
}
